#include "threadPool.hpp"


ThreadPool::ThreadPool(size_t thread_num):m_stop(false){
    for(size_t i = 0;i < thread_num;i++)
    {
        m_worker_threads.emplace_back(std::thread([this](){
            while(!m_stop.load()){
                std::function<void()> task;
                {
                    std::unique_lock<std::mutex> lock(m_queue_mtx);
                    m_cv.wait(lock,[this](){
                        return m_stop || !m_queue.empty();
                    });
                    if(m_stop.load())
                        return;
                    task = m_queue.front();
                    m_queue.pop();
                }
                task();
            }
        }));
    }
}


template<typename F,typename ...Args>
auto ThreadPool::enqueue(F&& f,Args&&... args) -> std::future<decltype(f(args...))>
{
    using reture_type = decltype(f(args...));
    if(m_stop.load())
        return std::future<reture_type()>();
    auto task = std::make_shared<std::packaged_task<reture_type()> >(std::bind(std::forward<F>(f),std::forward<Args>(args)...));
    std::future<reture_type> res = task->get_future();
    {
        std::unique_lock<std::mutex> lock(m_queue_mtx);
        if(m_stop.load())
            throw std::runtime_error("thread pool stoped.");
        m_queue.emplace([task](){
            (*task)();
        });
    }
    m_cv.notify_one();
    return res;
}

ThreadPool::~ThreadPool()
{
    m_stop.store(false);
    m_cv.notify_all();
    for(int i = 0;i < m_worker_threads.size();i++)
    {
        m_worker_threads[i].join();
    }
}


